package csm.uttils.encrypt;


/**
 * Define el comportamiento que es exigible para una clase que realice trabajos de 
 * encriptacion en base a metodos tradicionales. Se supone un "alfabeto" compuesto
 * de ciertos caracteres, y ese alfabeto esta almacenado en la constante ALFABETO
 * provista por esta clase.
 * 
 * Patron aplicado: Strategy.
 * 
 * @author Ing. Valerio Frittelli
 * @version Julio de 2009
 */
public abstract class Encrypter
{
    /**
     *  El alfabeto base aceptado.
     */
    public static final String ALFABETO = " ABCDEFGHIJKLMNÑOPQRSTUVWXYZabcdefghijklmnñopqrstuvwxyz.,;:?!0123456789";
    
    protected String mensaje;     // el mensaje abierto (mensaje a encriptar)
    protected String encriptado;  // el mensaje encriptado
    
    /**
     *  Inicializa el encriptador con un mensaje abierto tomado como parametro. Si el parametro es null, el
     *  mensaje a encriptar se inicializa como una cadena vacia (""), lo cual deberea provocar que el metodo
     *  code() retorne null. El constructor tambien inicia como cadena vacea el mensaje encriptado (que se
     *  obtiene con getEncrypted()) y esto tambien deberea provocar que el metodo decode() retorne null.
     */
    public Encrypter ( String mens )
    {
        if ( mens == null ) mens = "";
        mensaje = mens;
        encriptado = "";
    }   
    
    /**
     *  Retorna el ultimo mensaje abierto que deberia ser usado la proxima vez que se invoque a code().
     *  @return el mensaje abierto.
     */
    public String getOpenMessage()
    {
        return mensaje;
    }
    
    /**
     *  Cambia el mensaje a encriptar. Si el nuevo mensaje es null, el mensaje a encriptar se inicia como cadena 
     *  vacia (""), lo que deberia provocar que una invocacion a code() retorne null. En todos los casos, tambien
     *  se inicia como cadena vacia el mensaje encriptado, lo que deberia provocar que una nueva invocacion a decode()
     *  retorne null.
     *  @param mens el nuevo mensaje a encriptar.
     */
    public void setOpenMessage( String mens )
    {
        if ( mens == null ) mens = "";
        mensaje = mens;
        encriptado = "";
    }
    
    /**
     * Retorna el ultimo mensaje encriptado. Si el valor retornado es null, es que la ultima invocacion a code()
     * no pudo completar el proceso (posiblemente por caracteres extranios en el mensaje abierto). Si el valor retornado
     * es la cadena vacia (""), es que nunca se invoca code() o bien es que el mensaje abierto fue cambiado (con
     * setOpenMessage()) desde la ultima vez que se invoca a code().
     * @return el ultimo mensaje encriptado.
     */
    public String getEncrypted()
    {
        return encriptado;
    }
    
    /**
     *  Retorna una cadena con el ultimo mensaje abierto trabajado por el encriptador y la ultima encriptacion
     *  conocida para ese mensaje (que puede ser null o la cadena vacia si el proceso de encriptacion fallo o
     *  nunca se activa).
     *  @return una cadena con el ultimo mensaje abierto y la ultima encriptacion conocida para el.
     */
    public String toString()
    {
        return "Ultimo mensaje abierto: " + mensaje + "  -  Ultima encriptacion conocida: " + encriptado;
    }
    
    /**
     *  Encripta un mensaje formado por los sembolos del alfabeto base, siguiendo alguna tecnica
     *  de encriptacion que sera provista por las clases derivadas. El metodo retorna una cadena con el mensaje
     *  encriptado (o null si el proceso no pudo realizarse por haber caracteres extranios en el mensaje abierto),
     *  pero de todos modos el mensaje encriptado queda almacenado en la clase y puede recuperarse directamente 
     *  usando getEncrypted().
     *  @return una cadena con el mensaje encriptado, o null si el mensaje abierto no pudo encriptarse (debido 
     *          a que algun caracter de ese mensaje original no figuraba en el alfabeto base aceptado).
     */
    public abstract String code ( );
    
    /**
     *  Desencripta un mensaje, siguiendo alguna tecnica de encriptacion que sera provista por las
     *  clases derivadas. El mensaje encriptado se supone creado con la misma tecnica que sera usada
     *  para desencriptar, y el mensaje obtenido contendra exclusivamente caracteres del alfabeto base aceptado.
     *  El metodo retorna una cadena con el mensaje abierto (o null si el proceso no pudo realizarse por haber
     *  caracteres extranios en el mensaje encriptado), pero de todos modos el mensaje abierto queda almacenado en
     *  la clase y puede recuperarse directamente usando getOpenMessage().
     *  @return una cadena con el mensaje desencriptado, o null el proceso no pudo hacerse (debido a que algun
     *          caracter del mensaje encriptado no era valido).
     */
    public abstract String decode ( );
    
    /**
     * Comprueba si la cadena tomada como parametro esta formada exclusivamente por caracteres del alfabeto base
     * aceptado por el encriptador.
     * @param cad la cadena a comprobar
     * @return true si todos los caracteres son validos, o false en caso contrario (o si cad es null).
     */
    protected boolean isOk ( String cad )
    {
      if (cad == null) return false;
      
      for (int i = 0; i < cad.length(); i++) 
      {
          if ( Encrypter.ALFABETO.indexOf( cad.charAt(i) ) == -1 ) return false;
      }    
      return true;
    }

    public void setEncripted( String enc)
    {
        encriptado = enc;
    }
}
